package helper.scxml.scxml2.zone.t2.case3_factoryLines

import helper.base.A2LHM
import helper.base.BaseTypeHelper.toIntRange
import helper.base.LHMHelper.A2LHMExpand.add
import helper.base.LHMHelper.A2LHMExpand.makeA2LHM
import helper.base.LHMHelper.A3LHM.Companion.makeA3LHM
import helper.base.PrintHelper.toPrettyString
import helper.base.ZoneConstraintHelper.Constraint
import helper.base.debug.DebugHelper.DebuggerList
import helper.base.debug.DebugHelper.DebuggerList.Companion.makeDebuggerList
import helper.base.math.TreeHelper.T2HierarchyStructure
import helper.base.math.TreeHelper.T2HierarchyStructure.Companion.makeT2ParentChildRelations
import helper.scxml.scxml2.zone.t2.ConfigHelper.Config
import helper.scxml.scxml2.zone.t2.ConfigHelper.Config.ConfigBoolFun.aConfigTrueFun
import helper.scxml.scxml2.zone.t2.ConfigHelper.Config.ConfigBoolFun.aHeapNotContainsEventFun
import helper.scxml.scxml2.zone.t2.NoteRunResultFun
import helper.scxml.scxml2.zone.t2.ScxmlEnvHelper
import helper.scxml.scxml2.zone.t2.ScxmlEnvHelper.ScxmlEnv
import helper.scxml.scxml2.zone.t2.T3SNodeUnitHelper.ERT3SNodeUnit
import helper.scxml.scxml2.zone.t2.T3SNodeUnitHelper.ERT3SNodeUnit.Companion.makeERT3SNodeUnit
import helper.scxml.scxml2.zone.t2.ZoneEnvHelper.AssignAction.Companion.makeAssignAction
import helper.scxml.scxml2.zone.t2.ZoneEnvHelper.Edge.Companion.makeEdge
import helper.scxml.scxml2.zone.t2.ZoneEnvHelper.IStrategyEx
import helper.scxml.scxml2.zone.t2.ZoneEnvHelper.StringActionListLHM.Companion.makeStringActionListLHM
import helper.scxml.scxml2.zone.t2.ZoneLearningHelper.IDsDFun
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.CalObj.D4DFun.Companion.getD4DFun
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.CalObj.D5DFun
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.CalObj.D5DFun.Companion.getD5DFun
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.FLEnv.Companion.aPMs
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.FLEnv.Companion.aProductionMachineLine
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.FLEnv.Companion.byNameGetPM
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.M4SubT2SNodeUnitLHM.Companion.makeM4SubT2SNodeUnitLHM
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.ProductionArgTuple.Companion.makeProductionArgTuple
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.ProductionMachine.Companion.makeProductionMachine
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.ProductionMachineLine.Companion.makeProductionMachineLine
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.StrategyObj.ER.makeFLStrategy
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.StrategyObj.Env.getT1StringEnvStrategyLHM
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.StrategyObj.Ren.getB2D2UniformStringRenStrategyLHM
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.StrategyObj.Ren.getT1StringRenStrategyLHM
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.StrategyObj.Ren.getT2StringRenStrategyLHM
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper.StrategyObj.Ren.getUniformStringRenStrategyLHM
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FunArgHelperKt.ZoneStateStringFunArgHelper.aForMachineGetZoneStateFunction
import helper.scxml.strategy.TotalStrategyHelper.I2SNode
import helper.scxml.strategy.TotalStrategyHelper.KREWTuple.Companion.makeKREWTuple
import helper.scxml.strategy.TotalStrategyHelper.KREWsTuple
import helper.scxml.strategy.TotalStrategyHelper.KREWsTuple.Companion.makeKREWsTuple
import helper.scxml.strategy.TotalStrategyHelper.REWTuple.Companion.makeREWTuple
import helper.scxml.strategy.TotalStrategyHelper.SNode.Companion.makeSNode
import helper.scxml.strategy.sNodeUnit.SNodeUnitHelper.ISNodeUnit
import helper.scxml.strategy.sNodeUnit.T2SNodeUnitHelper.SubT2SNodeUnit
import helper.scxml.strategy.sNodeUnit.T2SNodeUnitHelper.SubT2SNodeUnit.Companion.makeSubT2SNodeUnit
import kotlin.math.max

object FLEnvHelper {
    // ProductionArgTuple 类定义了生产过程中的参数元组
    class ProductionArgTuple(
        val aLocationName: String, // 生产位置的名称
        val inVars: List<String>, // 输入变量名列表
        val outVars: List<String>, // 输出变量名列表
        val time: Int, // 生产所需时间
    ) {
        // 提供静态方法来构造 ProductionArgTuple 实例
        companion object {
            // 标准构造方法
            fun makeProductionArgTuple(
                aLocationName: String,
                inVars: List<String>,
                outVars: List<String>,
                time: Int,
            ): ProductionArgTuple {
                return ProductionArgTuple(aLocationName, inVars, outVars, time)
            }

            // 简化构造方法，用于单个输入和输出变量
            fun makeProductionArgTuple(
                aLocationName: String,
                inVar1: String,
                outVar1: String,
                time: Int,
            ): ProductionArgTuple {
                return makeProductionArgTuple(aLocationName, listOf(inVar1), listOf(outVar1), time)
            }

            // 构造方法，仅包含输出变量和时间，无输入变量
            fun makeProductionArgTuple(
                aLocationName: String,
                outVar1: String,
                time: Int,
            ): ProductionArgTuple {
                return makeProductionArgTuple(aLocationName, listOf(), listOf(outVar1), time)
            }
        }

        // 覆写 toString 方法以提供类内容的字符串表示
        override fun toString(): String {
            return "ProductionArgTuple(aLocationName='$aLocationName', inVars=$inVars, outVars=$outVars, time=$time)"
        }
    }

    // ProductionMachine 类定义了一个生产机械的配置
    class ProductionMachine(
        val name: String, // 机械名称
        val aProductionArgTupleList: List<ProductionArgTuple>, // 生产参数元组列表
        val aStartLocationName: String, // 生产起始位置名称
        val aEndLocationName: String, // 生产结束位置名称
    ) {
        // 提供静态方法来构造 ProductionMachine 实例
        companion object {
            // 标准构造方法
            fun makeProductionMachine(
                name: String,
                aProductionArgTupleList: List<ProductionArgTuple>,
                aStartLocationName: String,
                aEndLocationName: String,
            ): ProductionMachine {
                return ProductionMachine(name, aProductionArgTupleList, aStartLocationName, aEndLocationName)
            }

            // 简化构造方法，用于包含两个生产参数元组的情况
            fun makeProductionMachine(
                name: String,
                varPair1: ProductionArgTuple,
                varPair2: ProductionArgTuple,
                aStartLocationName: String,
                aEndLocationName: String,
            ): ProductionMachine {
                return makeProductionMachine(name, listOf(varPair1, varPair2), aStartLocationName, aEndLocationName)
            }
        }

        // 覆写 toString 方法以提供类内容的字符串表示
        override fun toString(): String {
            return "ProductionMachine(name='$name', aProductionArgTupleList=$aProductionArgTupleList, aStartLocationName='$aStartLocationName', aEndLocationName='$aEndLocationName')"
        }
    }

    // 定义一个 lambda 函数，用于判断一个生产位置是否有足够的输入变量
    val aZoneStateProductionInVarsEnough: (Config, ProductionArgTuple) -> Boolean = { zs, p ->
        p.inVars.all {
            zs.byNameFindC(it).getPointD() > 0
        }
    }

    // ProductionMachineLine 类定义了一个生产线，包含两类生产机械
    class ProductionMachineLine(
        val aT1PMs: List<ProductionMachine>, // 类型1的生产机械列表
        val aT2PMs: List<ProductionMachine>, // 类型2的生产机械列表
    ) {
        // 提供静态方法来构造 ProductionMachineLine 实例
        companion object {
            fun makeProductionMachineLine(
                aT1PMs: List<ProductionMachine>,
                aT2PMs: List<ProductionMachine>,
            ): ProductionMachineLine {
                return ProductionMachineLine(aT1PMs, aT2PMs)
            }
        }

        // 通过延迟初始化合并两类生产机械为一个列表
        val aPMs: List<ProductionMachine> by lazy {
            aT1PMs + aT2PMs
        }
    }

    class FLEnv(override val timeNeedEnd: Int) : ScxmlEnv() {
        companion object {
            fun makeFLEnv(timeNeedEnd: Number = 60) = FLEnv(timeNeedEnd.toInt())

            val aProductionMachineLine: ProductionMachineLine by lazy {
                makeProductionMachineLine(
                    listOf(
                        makeProductionMachine(
                            "sM1",
                            makeProductionArgTuple("1", "A1", 2),
                            makeProductionArgTuple("2", "A2", 3),
                            "0",
                            "3",
                        ),
                        makeProductionMachine(
                            "sM2",
                            makeProductionArgTuple("1", "B1", 2),
                            makeProductionArgTuple("2", "B2", 3),
                            "0",
                            "3",
                        ),
                    ),
                    listOf(
                        makeProductionMachine(
                            "sM3",
                            makeProductionArgTuple("1", "A1", "A1C1", 3),
                            makeProductionArgTuple("2", "B1", "B1C2", 4),
                            "0",
                            "3",
                        ),
                        makeProductionMachine(
                            "sM4",
                            makeProductionArgTuple("1", "A2", "A2D1", 3),
                            makeProductionArgTuple("2", "B2", "B2D2", 4),
                            "0",
                            "3",
                        ),
                    ),
                )
            }

            val aPMs: List<ProductionMachine> by lazy {
                aProductionMachineLine.aPMs
            }

            val aPMNames: List<String> by lazy {
                aPMs.map {
                    it.name
                }
            }

            val mNameFMLHM: A2LHM<String, ProductionMachine> by lazy {
                val lhm = makeA2LHM<String, ProductionMachine>()
                aPMs.forEach {
                    lhm.add(it.name, it)
                }
                lhm
            }

            fun byNameGetPM(name: String) = mNameFMLHM[name]!!
        }

        override fun printlnHIF() {
            super.printlnHIF()
            println("-".repeat(60))
            println("aPMs:")
            println(aPMs.toPrettyString())
        }

        override val aWithoutClocksTheVars by lazy {
            val res = arrayListOf<String>()
            aPMs.forEach {
                it.aProductionArgTupleList.forEach {
                    it.outVars.forEach {
                        res.add(it)
                    }
                }
            }
            res
        }

        override val allVars: List<String> by lazy {
            clocks + aWithoutClocksTheVars
        }

        override val aT1LsStringFun: ArrayList<String>.() -> String by lazy {
            {
                this.sortedBy {
                    when {
                        it.startsWith("sM1") -> 0
                        it.startsWith("sM2") -> 1
                        it.startsWith("sM3") -> 2
                        it.startsWith("sM4") -> 3
                        else -> 4
                    }
                }.joinToString(separator = ",")
            }
        }

        override val aT1CsStringFun: ArrayList<Constraint>.() -> String by lazy {
            {
                this.filter {
                    val vsString = it.getVariablesString()
                    vsString == "t" || it.getPointD() > 0
                }.joinToString(",") {
                    it.toStr0()
                }
            }
        }

        //层次关系
        override val aStateH: T2HierarchyStructure<String> by lazy {
            makeT2ParentChildRelations<String>().also { relations ->
                relations.addRelations(null, aPMNames)
                aPMs.forEach {
                    val name = it.name
                    val tempList = arrayListOf<String>()
                    tempList.add("${name}${it.aStartLocationName}")
                    it.aProductionArgTupleList.forEach {
                        tempList.add("${name}${it.aLocationName}")
                    }
                    tempList.add("${name}${it.aEndLocationName}")
                    relations.addRelations(
                        name,
                        tempList,
                    )
                }
            }
        }

        override val aStateI: LinkedHashMap<String?, LinkedHashSet<String>> by lazy {
            makeA2LHM<String?, LinkedHashSet<String>>().also { lhm ->
                //并发状态有多个直接孩子状态
                lhm[null] = LinkedHashSet(aPMNames)
                //复合状态只有1个直接孩子状态
                aPMs.forEach {
                    val name = it.name
                    lhm[name] = linkedSetOf("${name}${it.aStartLocationName}")
                }
                //其他的都是原子状态
            }
        }

        //如果是并发状态，则需要所有子状态都final，并发状态才算final
        override val aStateF: LinkedHashMap<String, LinkedHashSet<String>> by lazy {
            LinkedHashMap<String, LinkedHashSet<String>>().also { lhm ->
                aPMs.forEach {
                    val name = it.name
                    lhm[name] = linkedSetOf("${name}${it.aEndLocationName}")
                }
            }
        }

        //边
        override val aStateEventStateLHM = makeA3LHM<String, String, String>().also { lhm ->
            aPMs.forEach { aPM ->
                val name = aPM.name
                val tempList = arrayListOf(
                    makeEdge(
                        "${name}${aPM.aStartLocationName}",
                        "${name}${aPM.aEndLocationName}",
                    ),
                )
                aPM.aProductionArgTupleList.forEach {
                    tempList.add(
                        makeEdge(
                            "${name}${aPM.aStartLocationName}",
                            "${name}${it.aLocationName}",
                        ),
                    )
                    tempList.add(
                        makeEdge(
                            "${name}${it.aLocationName}",
                            "${name}${aPM.aStartLocationName}",
                        ),
                    )
                }
                tempList.forEach {
                    lhm.addIfAbsent(
                        it.locationStart,
                        it.edgeName,
                        it.locationEnd,
                    )
                }
            }
        }

        //最大停留时间
        override val stateStayMaxLHM by lazy {
            makeA2LHM<String, Int>().also { lhm ->
                aPMs.forEach {
                    val name = it.name
                    lhm.add("${name}${it.aStartLocationName}", 0)
                    it.aProductionArgTupleList.forEach {
                        lhm.add("${name}${it.aLocationName}", it.time)
                    }
                    lhm.add("${name}${it.aEndLocationName}", 0)
                }
            }
        }

        //进入条件
        override val aStateEnterConstraintLHM by lazy {
            val lhm = makeA2LHM<String, (Config) -> Boolean>()
            aProductionMachineLine.aT2PMs.forEach { aPM ->
                aPM.aProductionArgTupleList.forEach { aIOPair ->
                    lhm.add("${aPM.name}${aIOPair.aLocationName}") { zs ->
                        aIOPair.inVars.all {
                            zs.byNameFindC(it).getPointD() > 0
                        }
                    }
                }
            }
            lhm
        }

        //进入动作
        override val stateEnterActionLHM = makeStringActionListLHM().also { lhm ->
            aProductionMachineLine.aT2PMs.forEach { aPM ->
                aPM.aProductionArgTupleList.forEach { aIOPair ->
                    aIOPair.inVars.forEach {
                        lhm.add(
                            "${aPM.name}${aIOPair.aLocationName}",
                            arrayListOf(makeAssignAction(it) { max(it - 1, 0.0) }),
                        )
                    }
                }
            }
        }

        //退出动作
        override val stateExitActionLHM = makeStringActionListLHM().also { lhm ->
            aProductionMachineLine.aPMs.forEach { aPM ->
                aPM.aProductionArgTupleList.forEach { aIOPair ->
                    aIOPair.outVars.forEach {
                        lhm.add(
                            "${aPM.name}${aIOPair.aLocationName}",
                            arrayListOf(makeAssignAction(it) { it + 1 }),
                        )
                    }
                }
            }
        }

        override val aStateNoteRunResultFunLHM by lazy {
            makeA2LHM<String, NoteRunResultFun>().also { lhm ->
                aPMs.forEach { aM ->
                    lhm["${aM.name}0"] = ScxmlEnvHelper.env_tvsNoteRunResultFun_fun(this)
                }
            }
        }

        override fun doWhenEnd(nowConfig: Config, debuggerList: DebuggerList) {
            nowConfig.byNameFindC(tClock).setPointD(timeNeedEnd)
        }

        fun aT0Calculate(
            aSNU: ISNodeUnit,
            repeatTimes: Int = 1000,
            debuggerList: DebuggerList = makeDebuggerList(),
        ): A2LHM<String, Double> {
            return aT0Calculate(
                aSNU = aSNU,
                repeatTimes = repeatTimes,
                aLsStringFun = aT1LsStringFun,
                aCsStringFun = aT1CsStringFun,
                debuggerList = debuggerList,
            )
        }
    }

    class M4SubT2SNodeUnitLHM : A2LHM<String, SubT2SNodeUnit>() {
        companion object {
            fun makeM4SubT2SNodeUnitLHM(
                m1SubT2SNodeUnit: SubT2SNodeUnit = makeSubT2SNodeUnit(),
                m2SubT2SNodeUnit: SubT2SNodeUnit = makeSubT2SNodeUnit(),
                m3SubT2SNodeUnit: SubT2SNodeUnit = makeSubT2SNodeUnit(),
                m4SubT2SNodeUnit: SubT2SNodeUnit = makeSubT2SNodeUnit(),
            ): M4SubT2SNodeUnitLHM {
                return M4SubT2SNodeUnitLHM().apply {
                    this["sM1"] = m1SubT2SNodeUnit
                    this["sM2"] = m2SubT2SNodeUnit
                    this["sM3"] = m3SubT2SNodeUnit
                    this["sM4"] = m4SubT2SNodeUnit
                }
            }
        }
    }

    object StrategyObj {
        object Env {
            fun getT1StringEnvStrategyLHM(): A2LHM<String, SubT2SNodeUnit> {
                val lhm = makeA2LHM<String, SubT2SNodeUnit>()

                aProductionMachineLine.aPMs.forEach {dev->
                    val devName = dev.name

                    val env = makeSubT2SNodeUnit()
                    env.funLHM.add(null, aForMachineGetZoneStateFunction(devName))

                    dev.aProductionArgTupleList.forEach {
                        val aLocationName = it.aLocationName
                        val key = "${devName}${aLocationName}"
                        val edge = "${devName}${aLocationName}${devName}0"
                        env.addSNode(
                            null,
                            key,
                            linkedMapOf(
                                //这个"1"是任意的，只要不是空字符串就行
                                aConfigTrueFun to makeKREWTuple("1", it.time, edge, 1),
                            ),
                            aHeapNotContainsEventFun,
                        )
                    }

                    lhm.add(devName, env)
                }
                return lhm
            }
        }

        object Ren {
            /**
             * 都选制造第一个
             */
            fun getT1StringRenStrategyLHM(): A2LHM<String, SubT2SNodeUnit> {
                val lhm = makeA2LHM<String, SubT2SNodeUnit>()
                fun aFun1(sMi: String) {
                    val ren = makeSubT2SNodeUnit()
                    ren.funLHM.add(null, aForMachineGetZoneStateFunction(sMi))
                    ren.addSNode(
                        null,
                        "${sMi}0",
                        linkedMapOf(
                            aConfigTrueFun to makeKREWTuple(
                                "1", 0, "${sMi}0${sMi}1", 1
                            )
                        ),
                        aHeapNotContainsEventFun,
                    )

                    lhm.add(sMi, ren)
                }
                aFun1("sM1")
                aFun1("sM2")
                fun aFun2(sMi: String, aV1: String) {
                    val ren = makeSubT2SNodeUnit()
                    ren.funLHM.add(null, aForMachineGetZoneStateFunction(sMi))

                    ren.addSNode(
                        null,
                        "${sMi}0",
                        linkedMapOf(
                            { zs: Config ->
                                zs.byNameFindC(aV1).getPointD() > 0
                            } to makeKREWTuple("1", 0, "${sMi}0${sMi}1", 1),
                        ),
                        aHeapNotContainsEventFun,
                    )

                    lhm.add(sMi, ren)
                }
                aFun2("sM3", "A1")
                aFun2("sM4", "A2")
                return lhm
            }

            fun getT2StringRenStrategyLHM(): A2LHM<String, SubT2SNodeUnit> {
                val lhm = makeA2LHM<String, SubT2SNodeUnit>()
                fun aFun1(
                    sMi: String,
                    p1: String,
                    p2: String,
                ) {
                    val ren = makeSubT2SNodeUnit()
                    ren.funLHM.add(null, aForMachineGetZoneStateFunction(sMi))
                    ren.addSNode(
                        null,
                        "${sMi}0",
                        linkedMapOf(
                            { zs: Config ->
                                zs.byNameFindC(p1).getPointD() <= zs.byNameFindC(p2).getPointD()
                            } to makeKREWTuple("1", 0, "${sMi}0${sMi}1", 1),
                            { zs: Config ->
                                zs.byNameFindC(p2).getPointD() <= zs.byNameFindC(p1).getPointD()
                            } to makeKREWTuple("2", 0, "${sMi}0${sMi}2", 1),
                        ),
                        aHeapNotContainsEventFun,
                    )

                    lhm.add(sMi, ren)
                }
                aFun1("sM1", "A1", "A2")
                aFun1("sM2", "B1", "B2")
                fun aFun2(
                    sMi: String,
                    aV1a: String,
                    aV1b: String,
                    aV2a: String,
                    aV2b: String,
                ) {
                    val ren = makeSubT2SNodeUnit()
                    ren.funLHM.add(null, aForMachineGetZoneStateFunction(sMi))
                    ren.addSNode(
                        null,
                        "${sMi}0",
                        linkedMapOf(
                            { zs: Config ->
                                zs.byNameFindC(aV1a).getPointD() > 0 && zs.byNameFindC(aV1b)
                                    .getPointD() <= zs.byNameFindC(aV2b).getPointD()
                            } to makeKREWTuple("1", 0, "${sMi}0${sMi}1", 1),
                            { zs: Config ->
                                zs.byNameFindC(aV2a).getPointD() > 0 && zs.byNameFindC(aV2b)
                                    .getPointD() <= zs.byNameFindC(aV1b).getPointD()
                            } to makeKREWTuple("2", 0, "${sMi}0${sMi}2", 1),
                        ),
                        aHeapNotContainsEventFun,
                    )

                    lhm.add(sMi, ren)
                }
                aFun2("sM3", "A1", "A1C1", "B1", "B1C2")
                aFun2("sM4", "A2", "A2D1", "B2", "B2D2")
                return lhm
            }

            fun aFLEnvRenStrategyAddUniformNode(
                ren: SubT2SNodeUnit,
                aProductionMachine: ProductionMachine,
                location: String,
                aSNode: I2SNode,
                intRange: IntRange = 0.toIntRange(),
            ) {
                val sMi = aProductionMachine.name

                val aLHM = makeA2LHM<(Config) -> Boolean, KREWsTuple>()
                aLHM.add(
                    { zs ->
                        aProductionMachine.aProductionArgTupleList.all {
                            it.inVars.all {
                                zs.byNameFindC(it).getPointD() > 0
                            }
                        }
                    },
                    makeKREWsTuple(
                        "u0",
                        aProductionMachine.aProductionArgTupleList.withIndex().map { (i, it) ->
                            makeREWTuple(0, "${location}${sMi}${i + 1}", 1)
                        },
                    ),
                )

                aProductionMachine.aProductionArgTupleList.withIndex().forEach { (i, it) ->
                    aLHM.add(
                        { zs ->
                            aZoneStateProductionInVarsEnough(zs, it)
                        },
                        makeKREWsTuple(
                            "u${i + 1}",
                            listOf(
                                makeREWTuple(intRange, "${location}${sMi}${i + 1}", 1),
                            ),
                        ),
                    )
                }

                ren.addAddedBoolFunSNode(
                    aSNode,
                    aLHM,
                )
            }

            fun getUniformStringRenStrategyLHM(intRange: IntRange = 0.toIntRange()): A2LHM<String, SubT2SNodeUnit> {
                val lhm = makeA2LHM<String, SubT2SNodeUnit>()
                aPMs.forEach { aProductionMachine: ProductionMachine ->
                    val sMi = aProductionMachine.name
                    val ren = makeSubT2SNodeUnit()
                    ren.funLHM.add(null, aForMachineGetZoneStateFunction(sMi))
                    val location = "${sMi}0"
                    val aSNode = makeSNode()
                    ren.relationLHM.add(null, location, aSNode)
                    aFLEnvRenStrategyAddUniformNode(
                        ren,
                        aProductionMachine,
                        location,
                        aSNode,
                        intRange,
                    )
                    lhm.add(sMi, ren)
                }
                return lhm
            }

            fun getB2D2UniformStringRenStrategyLHM(): A2LHM<String, SubT2SNodeUnit> {
                val lhm = makeA2LHM<String, SubT2SNodeUnit>()
                aPMs.forEach { aProductionMachine: ProductionMachine ->
                    val sMi = aProductionMachine.name
                    val ren = makeSubT2SNodeUnit()
                    ren.funLHM.add(null, aForMachineGetZoneStateFunction(sMi))
                    lhm.add(sMi, ren)
                }
                byNameGetPM("sM1").let { aProductionMachine: ProductionMachine ->
                    val sMi = aProductionMachine.name
                    val ren = lhm[sMi]!!
                    val location = "${sMi}0"
                    val aSNode = makeSNode()
                    ren.relationLHM.add(null, location, aSNode)
                    val aLHM = makeA2LHM<(Config) -> Boolean, KREWsTuple>()
                    aLHM.add(
                        aConfigTrueFun,
                        makeKREWsTuple(
                            "1",
                            listOf(
                                makeREWTuple(0, "${location}${sMi}1", 1)
                            ),
                        ),
                    )
                    ren.addAddedBoolFunSNode(
                        aSNode,
                        aLHM,
                    )
                }
                byNameGetPM("sM2").let { aProductionMachine: ProductionMachine ->
                    val sMi = aProductionMachine.name
                    val ren = lhm[sMi]!!
                    val location = "${sMi}0"
                    val aSNode = makeSNode()
                    ren.relationLHM.add(null, location, aSNode)
                    val aLHM = makeA2LHM<(Config) -> Boolean, KREWsTuple>()
                    aLHM.add(
                        aConfigTrueFun,
                        makeKREWsTuple(
                            "2",
                            listOf(
                                makeREWTuple(0, "${location}${sMi}2", 1)
                            ),
                        ),
                    )
                    ren.addAddedBoolFunSNode(
                        aSNode,
                        aLHM,
                    )
                }
                byNameGetPM("sM3").let { aProductionMachine: ProductionMachine ->
                    val sMi = aProductionMachine.name
                    val ren = lhm[sMi]!!
                    val location = "${sMi}0"
                    val aSNode = makeSNode()
                    ren.relationLHM.add(null, location, aSNode)
                    val aLHM = makeA2LHM<(Config) -> Boolean, KREWsTuple>()
                    aLHM.add(
                        { zs ->
                            aZoneStateProductionInVarsEnough(
                                zs,
                                aProductionMachine.aProductionArgTupleList[0],
                            )
                        },
                        makeKREWsTuple(
                            "1",
                            listOf(
                                makeREWTuple(0, "${location}${sMi}1", 1)
                            ),
                        ),
                    )
                    ren.addAddedBoolFunSNode(
                        aSNode,
                        aLHM,
                    )
                }
                byNameGetPM("sM4").let { aProductionMachine: ProductionMachine ->
                    val sMi = aProductionMachine.name
                    val ren = lhm[sMi]!!
                    val location = "${sMi}0"
                    val aSNode = makeSNode()
                    ren.relationLHM.add(null, location, aSNode)
                    val aLHM = makeA2LHM<(Config) -> Boolean, KREWsTuple>()
                    aLHM.add(
                        { zs ->
                            aZoneStateProductionInVarsEnough(
                                zs,
                                aProductionMachine.aProductionArgTupleList[1],
                            )
                        },
                        makeKREWsTuple(
                            "2",
                            listOf(
                                makeREWTuple(0, "${location}${sMi}2", 1)
                            ),
                        ),
                    )
                    ren.addAddedBoolFunSNode(
                        aSNode,
                        aLHM,
                    )
                }
                return lhm
            }
        }

        object ER {
            fun makeFLStrategy(
                aStringRenStrategyLHM: A2LHM<String, SubT2SNodeUnit>,
                aStringEnvStrategyLHM: A2LHM<String, SubT2SNodeUnit> = getT1StringEnvStrategyLHM(),
            ): ERT3SNodeUnit {
                return makeERT3SNodeUnit(
                    FLEnv.aPMNames,
                    aStringRenStrategyLHM,
                    aStringEnvStrategyLHM,
                )
            }

            /**
             * 都选制造第一个
             */
            fun makeT1FLStrategy(): ERT3SNodeUnit {
                return makeFLStrategy(
                    getT1StringRenStrategyLHM(),
                )
            }

            /**
             * 造一造二的概率都一样
             */
            fun makeT2FLStrategy(): ERT3SNodeUnit {
                return makeFLStrategy(
                    getT2StringRenStrategyLHM(),
                )
            }

            fun makeUniformFLStrategy(intRange: IntRange = 0.toIntRange()): ERT3SNodeUnit {
                return makeFLStrategy(
                    getUniformStringRenStrategyLHM(intRange)
                )
            }

            val aB2D2FLStrategy: ERT3SNodeUnit by lazy {
                makeFLStrategy(
                    getB2D2UniformStringRenStrategyLHM()
                )
            }
        }
    }

    object CalObj {
        class D4DFun(val aFun: (Double, Double, Double, Double) -> Double) : IDsDFun {
            companion object {
                fun getD4DFun(aFun: (Double, Double, Double, Double) -> Double) = D4DFun(aFun)
            }

            override fun aDsToString(vararg ds: Double): Double {
                return aFun(ds[0], ds[1], ds[2], ds[3])
            }
        }

        class D5DFun(val aFun: (Double, Double, Double, Double, Double) -> Double) : IDsDFun {
            companion object {
                fun getD5DFun(aFun: (Double, Double, Double, Double, Double) -> Double) = D5DFun(aFun)
            }

            override fun aDsToString(vararg ds: Double): Double {
                return aFun(ds[0], ds[1], ds[2], ds[3], ds[4])
            }
        }

        val aD4DFun1 = getD4DFun { aA1C1, aB1C2, aA2D1, aB2D2 ->
            300 - (5 * aA1C1 + 6 * aB1C2 + 6 * aA2D1 + 7 * aB2D2)
        }
        val aD5DFun1 = getD5DFun { t, aA1C1, aB1C2, aA2D1, aB2D2 ->
            (15000.0 - (5 * aA1C1 + 6 * aB1C2 + 6 * aA2D1 + 1000 * aB2D2)) / t
        }

        val aD5DFun2 = getD5DFun { t, aA1C1, aB1C2, aA2D1, aB2D2 ->
            400.0 - (5 * aA1C1 + 7 * aB1C2 + 7 * aA2D1 + 10 * aB2D2)
        }

        val bD5DFun2 = getD5DFun { t, aA1C1, aB1C2, aA2D1, aB2D2 ->
            480.0 - (5 * aA1C1 + 6 * aB1C2 + 6 * aA2D1 + 14 * aB2D2)
        }

        val aD5DFun3 = getD5DFun { t, aA1C1, aB1C2, aA2D1, aB2D2 ->
            400.0 - (5 * aA1C1 + 7 * aB1C2 + 7 * aA2D1 + 10 * aB2D2)
        }
    }

    object TimeAndCalObj {
        class TimeAndD5DFunClass(val time: Int, val aFun: D5DFun) {
            companion object {
                fun makeTimeAndD5DFunClass(time: Int, aFun: D5DFun) = TimeAndD5DFunClass(time, aFun)
            }
        }
    }

    class FLT3StrategyEx(val intRange: IntRange) : IStrategyEx<ERT3SNodeUnit> {
        companion object {
            fun makeFLT3StrategyEx(intRange: IntRange = 0.toIntRange()): FLT3StrategyEx {
                return FLT3StrategyEx(intRange)
            }
        }

        fun makeMyStrategy(aStringRenStrategyLHM: A2LHM<String, SubT2SNodeUnit>): ERT3SNodeUnit {
            return makeFLStrategy(
                aStringRenStrategyLHM = aStringRenStrategyLHM,
            )
        }

        override fun makeNewStrategy(): ERT3SNodeUnit {
            return makeMyStrategy(aStringRenStrategyLHM = makeM4SubT2SNodeUnitLHM())
        }

        override fun makeFixedStrategy(): ERT3SNodeUnit {
            return makeMyStrategy(aStringRenStrategyLHM = getUniformStringRenStrategyLHM(intRange = intRange))
        }
    }
}